package sim

import (
	"context"
	carpb "coolcar/v1/car/api/gen/v1"
	"coolcar/v1/car/mq"
	"go.uber.org/zap"
	"time"
)

type Controller struct {
	CarService carpb.CarServiceClient
	Sugar      *zap.SugaredLogger
	Subscriber mq.Subscriber
}

func (c *Controller) RunSimulations(ctx context.Context) {
	var cars []*carpb.CarEntity
	for {
		time.Sleep(3 * time.Second)
		res, err := c.CarService.GetCars(ctx, &carpb.GetCarsRequest{})
		if err != nil {
			c.Sugar.Errorf("failed to get cars: %v", err)
			continue
		}
		cars = res.Cars
		break
	}
	chMsg, cleanUp, err := c.Subscriber.Subscribe(ctx)
	defer cleanUp()
	if err != nil {
		c.Sugar.Errorf("failed to subscribe: %v", err)
		return
	}

	carChans := make(map[string]chan *carpb.Car)
	for _, car := range cars {
		ch := make(chan *carpb.Car)
		carChans[car.Id] = ch
		go c.SimulateCar(context.Background(), ch, car)
	}

	for carUpdate := range chMsg {
		ch := carChans[carUpdate.Id]
		if ch != nil {
			ch <- carUpdate.Car
		}
	}
}

func (c *Controller) SimulateCar(ctx context.Context, ch chan *carpb.Car, init *carpb.CarEntity) {
	cid := init.Id
	for carUpdate := range ch {
		if carUpdate.Status == carpb.CarStatus_UNLOCKING {
			_, err := c.CarService.UpdateCar(ctx, &carpb.UpdateCarRequest{
				Id:     cid,
				Status: carpb.CarStatus_UNLOCKED,
			})
			if err != nil {
				c.Sugar.Error("failed to unlock car", err)
			}
		} else if carUpdate.Status == carpb.CarStatus_LOCKING {
			_, err := c.CarService.UpdateCar(ctx, &carpb.UpdateCarRequest{
				Id:     cid,
				Status: carpb.CarStatus_LOCKED,
			})
			if err != nil {
				c.Sugar.Error("failed to lock car", err)
			}

		}
	}
}
